package axmlprinter2;

import android.util.Xml;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;

import axmlprinter2.res.AXmlResourceParser;

public class AXMLPrinter {
    private static final float[] RADIX_MULTS = {0.0039063F, 3.051758E-005F, 1.192093E-007F, 4.656613E-010F};

    private static final String[] DIMENSION_UNITS = {"px", "dip", "sp", "pt", "in", "mm", "", ""};

    private static final String[] FRACTION_UNITS = {"%", "%p", "", "", "", "", "", ""};

    public static XmlPullParser getAndroidManifest(InputStream inputStream) {
        if (inputStream == null) {
            log("Usage: AXMLPrinter <binary xml file>", new Object[0]);
            return null;
        }

        try {
            AXmlResourceParser parser = new AXmlResourceParser();
            parser.open(inputStream);
            StringBuilder indent = new StringBuilder(10);
            StringBuilder sb = new StringBuilder();
            String indentStep = "\t";
            int type = 0;
            while ((type = parser.next()) != 1) {
                switch (type) {
                    case 0:
                        sb.append(log("<?xml version=\"1.0\" encoding=\"utf-8\"?>", new Object[0]));
                        break;
                    case 1:
                        break;
                    case 2:
                        sb.append(log("%s<%s%s", new Object[]{indent, getNamespacePrefix(parser.getPrefix()), parser.getName()}));
                        indent.append(indentStep);

                        int namespaceCountBefore = parser.getNamespaceCount(parser.getDepth() - 1);
                        int namespaceCount = parser.getNamespaceCount(parser.getDepth());
                        for (int i = namespaceCountBefore; i != namespaceCount; i++) {
                            sb.append(log("%sxmlns:%s=\"%s\"", new Object[]{
                                    indent,
                                    parser.getNamespacePrefix(i),
                                    parser.getNamespaceUri(i)}));
                        }

                        for (int i = 0; i != parser.getAttributeCount(); i++) {
                            sb.append(log("%s%s%s=\"%s\"", new Object[]{indent,
                                    getNamespacePrefix(parser.getAttributePrefix(i)),
                                    parser.getAttributeName(i),
                                    getAttributeValue(parser, i)}));
                        }
                        sb.append(log("%s>", new Object[]{indent}));
                        break;
                    case 3:
                        indent.setLength(indent.length() - indentStep.length());
                        sb.append(log("%s</%s%s>", new Object[]{indent,
                                getNamespacePrefix(parser.getPrefix()),
                                parser.getName()}));
                        break;
                    case 4:
                        sb.append(log("%s%s", new Object[]{indent, parser.getText()}));
                        break;
                }
            }
            System.out.println(sb.toString());
            XmlPullParser p = Xml.newPullParser();
            p.setInput(new StringReader(sb.toString()));
            return p;
        } catch (XmlPullParserException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    private static String getNamespacePrefix(String prefix) {
        if ((prefix == null) || (prefix.length() == 0)) {
            return "";
        }
        return prefix + ":";
    }

    private static String getAttributeValue(AXmlResourceParser parser, int index) {
        int type = parser.getAttributeValueType(index);
        int data = parser.getAttributeValueData(index);
        if (type == 3) {
            return parser.getAttributeValue(index);
        }
        if (type == 2) {
            return String.format("?%s%08X", new Object[]{getPackage(data), Integer.valueOf(data)});
        }
        if (type == 1) {
            return String.format("@%s%08X", new Object[]{getPackage(data), Integer.valueOf(data)});
        }
        if (type == 4) {
            return String.valueOf(Float.intBitsToFloat(data));
        }
        if (type == 17) {
            return String.format("0x%08X", new Object[]{Integer.valueOf(data)});
        }
        if (type == 18) {
            return data != 0 ? "true" : "false";
        }
        if (type == 5) {
            return Float.toString(complexToFloat(data)) +
                    DIMENSION_UNITS[(data & 0xF)];
        }
        if (type == 6) {
            return Float.toString(complexToFloat(data)) +
                    FRACTION_UNITS[(data & 0xF)];
        }
        if ((type >= 28) && (type <= 31)) {
            return String.format("#%08X", new Object[]{Integer.valueOf(data)});
        }
        if ((type >= 16) && (type <= 31)) {
            return String.valueOf(data);
        }
        return String.format("<0x%X, type 0x%02X>", new Object[]{Integer.valueOf(data), Integer.valueOf(type)});
    }

    private static String getPackage(int id) {
        if (id >>> 24 == 1) {
            return "android:";
        }
        return "";
    }

    private static String log(String format, Object[] arguments) {
//        PrintStream p = System.out.printf(format, arguments);
//        System.out.println();
        return String.format(format + "\n", arguments);
    }

    public static float complexToFloat(int complex) {
        return (complex & 0xFFFFFF00) * RADIX_MULTS[(complex >> 4 & 0x3)];
    }
}
